#!/usr/bin/env python
# -*- coding: utf8 -*-
from threading import Thread
import sys
import socket
import traceback

from soccerbots.net import *
from soccerbots.core.structs import *

class UDPThread(Thread):
    def __init__(self, parent, server):
        Thread.__init__(self)
        self.parent = parent
        self.port = 12000
        self.server = server
        self.socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 
        self.net = BotsSocket(self.socket)
        
        binded = False
        while not binded:
            try:
                print "Binding UDP in",self.port,"..."
                self.socket.bind(("",self.port))
                binded = True
            except:
                self.port += 1

        self.net = BotsSocket(self.socket)

    def sendMovement(self, movement):
        msg = NetMessage()
        lines = movement.getLines()
        for line in lines:
            msg.append(line)

        self.net.sendMessage(msg, self.server)

    def finalize(self):
        self.socket.close()
    
    def run(self):
        error = False
        last_time = 0
        while not error:
            try:
                msg = self.net.readPlainMessage()
                print 'UDP Received !'
                time = int(strhex(msg.lines[0]))
                if time > last_time:
                    state = GameState.parseFromLines(msg.lines[1:])
                    state.time = time
                    self.parent.stateReceived(state)
                    last_time = time
            except:
                traceback.print_exc(file=sys.stdout)
                error = True

class Client(Thread):
    def __init__(self, app, server_addr='localhost', port=10000):
        Thread.__init__(self)
        self.app = app
        self.server_addr = server_addr
        self.server = (server_addr, port)
        self.port = port
        self.properties = None
        self.id = 0
        
        try:
            self.socketClient = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            self.socketClient.setblocking(1)
            self.socketClient.connect((server_addr,port))
        except:
            print "Can't connect to server:",server_addr,port
            sys.exit(-1)
        
        self.data = UDPThread(self, self.server)
        self.data.start()
        self.net = BotsSocket(self.socketClient)

    def connect(self):
        # CONNECTA
        msg = NetMessage('CONNECTA')
        msg.appendValue('Port',tohexstr(self.data.port))
        self.net.sendMessage(msg)

        # CONNECTA-ACK
        msg = self.net.readMessage()
        self.properties = {}
        if msg.type=='CONNECTA-ACK':
            for i in range(msg.numLines()):
                k,v = msg.getLine(i)
                self.properties[k] = strhex(v)
        else:
            raise RuntimeError

        self.max_lin_vel = self.properties['VLM']
        self.max_ang_vel = self.properties['VAM']
        self.id = int(self.properties['Id'])

    def inicia(self):
        #envia INICIA
        msg = NetMessage('INICI')
        msg.appendValue('Id', tohexstr(self.id))
        self.net.sendMessage(msg)

    def xiulet(self):
        msg = NetMessage('XIULET')
        self.net.sendMessage(msg)
    
    def goal(self):
        #envia GOL
        msg = NetMessage('GOL')
        self.net.sendMessage(msg)
   
    def fiPart(self):
        #envia GOL
        msg = NetMessage('FIPART')
        self.net.sendMessage(msg)
   
    def fiPartit(self):
        #envia GOL
        msg = NetMessage('FIPARTIT')
        self.net.sendMessage(msg)
   
    def fault(self, fault, team):
        #envia FALTA
        msg = NetMessage('FALTA')
        msg.appendValue('Equip', team)
        msg.appendValue('Tipus', fault)
        self.net.sendMessage(msg)

    def sendMovements(self, movement):
        movement.id = self.id
        self.data.sendMovement(movement)

    #Es rep l'estat de la partida des del servidor
    def stateReceived(self, state):
        self.app.stateReceived(state)

    def sendEvent(self, event):
        #send throw tcp
        pass

    def finalize(self):
        self.data.finalize()
        self.socketClient.close()

    def run(self):
        error = False
        while not error:
            try:
                msg = self.net.readMessage()
                print 'TCP Received: ',msg.type
                if msg.type == 'ESTATINI':
                    k,equip = msg.getLine(0)
                    k,atacant = msg.getLine(1)
                    state = GameState.parseFromLines(msg.lines[2:])
                    self.app.initStateReceived(int(equip),int(atacant),state)
                elif msg.type == 'GOL-ACK':
                    k,marcador = msg.getLine(0)
                    parts = marcador.split('-')
                    counter = (int(parts[0]),int(parts[1]))
                    self.app.updateCounter(counter)
                
                elif msg.type == 'FIPART-ACK':
                    self.app.newRound()
                    
            except:
                traceback.print_exc(file=sys.stdout)
                error = True
